import React, { memo, useEffect, useImperativeHandle, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { getLiveUrl, controlling, zoomWithBox } from './api';
import { useRequest } from 'ice';
import { useMemoizedFn } from 'ahooks';
import FlvJs from 'flv.js';

import { message, Spin } from 'antd';
import {
  AimOutlined,
  LoadingOutlined,
  SelectOutlined,
  UpOutlined,
  ZoomInOutlined,
  ZoomOutOutlined,
} from '@ant-design/icons';
import styles from './index.module.scss';
import VideoEmpty from '../VideoEmpty';

const LiveVideo = (
  props: {
    className?: string; // 最外层容器的样式
    append?: React.ReactNode;

    // 下面是播放需要的状态
    deviceEncoding: string;
    deviceChannel?: number;
    speed?: number;
    streamType?: 0 | 1;
  },
  ref: any,
) => {
  const { deviceEncoding, deviceChannel, speed, streamType } = props;

  // 请求播放地址url
  const { loading, data: url } = useRequest(() => getLiveUrl(deviceEncoding, deviceChannel, streamType), {
    refreshDeps: [deviceEncoding, deviceChannel, streamType],
    manual: false,
  });

  // 初始化视频播放控件
  const videoRef = useRef<any>();
  const [videoState, setVideoState] = useState('load');
  useJessibucaInit(videoRef, url, setVideoState);

  // 状态信息(load error play)
  const state = useMemo(() => {
    if (loading) return 'load';
    if (!url) return 'error';
    return videoState;
  }, [loading, url, videoState]);

  // 初始化3d缩放
  const syncZoom = useRef<Function>();
  const setDragState = useDrag(videoRef, syncZoom, (args) => {
    zoomWithBox({ deviceChannel, deviceEncoding, streamType, ...args });
  });

  // 视频播放控制接口
  const execCommad = useMemoizedFn(async (command: string, action?: 0 | 1, arg?: any) => {
    if (loading || videoState !== 'play') {
      return;
    }

    // 3dZoom
    if (command === '3D_ZOOM') {
      syncZoom.current = arg;
      setDragState(action === 0);
    } else {
      controlling({ deviceChannel, deviceEncoding, streamType, action, command, speed });
    }
  });

  // 视频播放控制接口
  useImperativeHandle(ref, () => ({ execCommad }), [execCommad]);

  // 渲染dom
  return <VideoPlayer videoRef={videoRef} state={state as any} className={props.className} append={props.append} />;

  // return (
  //   <div className={props.className} x-class="relative">
  //     {/* 视频容器 */}
  //     <div className="relative h-full">
  //       <video
  //         className="h-full w-full"
  //         style={{ visibility: videoState === 'load' ? 'hidden' : 'visible' }}
  //         controls
  //         ref={videoRef}
  //       />

  //       {/* 异常情况下的图片（没有播放地址） */}
  //       <VideoEmpty x-if={!loading && !url} className="absolute inset-0" />

  //       {/* 初始化中等待动画 */}
  //       <Spin
  //         x-if={loading || (url && videoState === 'load')}
  //         className="absolute inset-0 flex items-center justify-center bg-[#0000004d]"
  //         indicator={<LoadingOutlined style={{ fontSize: 48 }} spin />}
  //       />
  //     </div>

  //     {/*  其他的内容 */}
  //     {videoState !== 'load' && props.append && props.append(execCommad)}
  //   </div>
  // );
};

// 设备播放hooks
const useJessibucaInit = (
  ref: React.MutableRefObject<HTMLVideoElement>,
  url: string | undefined,
  onStateChange: any,
) => {
  const stateChangeRef = useMemoizedFn(onStateChange);

  useLayoutEffect(() => {
    if (!url || !ref.current) return;

    // const jessibuca = new (window as any).Jessibuca({
    //   container: ref.current,
    //   decoder: './decoder.js',
    //   videoBuffer: 0.2, // 缓存时长
    //   isResize: false,
    //   timeout: 3,
    //   text: '',
    //   debug: true,
    //   showBandwidth: false, // 显示网速
    //   hasAudio: false,
    //   operateBtns: {
    //     play: true, // 是否显示播放暂停按钮
    //     screenshot: true, // 是否显示截图按钮
    //     audio: true, // 是否显示声音按钮
    //     record: true, // 是否显示录制按钮
    //     fullscreen: true, // 是否显示全屏按钮
    //   },
    //   recordType: 'mp4',
    //   forceNoOffscreen: true,
    //   isNotMute: false,
    // });

    // jessibuca.on('play', () => {
    //   stateChangeRef('play');
    // });

    // jessibuca.on('error', (e) => {
    //   stateChangeRef('error');
    // });

    // jessibuca.on('load', () => {
    //   stateChangeRef('load');
    // });

    // jessibuca.play(url);

    // // jessibuca.on('pause', function (flag) {});

    // // jessibuca.on('fullscreen', function (flag) {});

    // jessibuca.setTimeout(10);

    // return () => {
    //   jessibuca.destroy();
    // };

    const instance = FlvJs.createPlayer(
      {
        type: 'flv',
        url,
        isLive: true,
        hasAudio: false,
        hasVideo: true,
      },
      {
        enableStashBuffer: true,
        autoCleanupSourceBuffer: true,
        lazyLoad: false,
        lazyLoadMaxDuration: 15,
      },
    );
    instance.attachMediaElement(ref.current);

    instance.on(FlvJs.Events.METADATA_ARRIVED, () => {
      stateChangeRef('play');
    });
    instance.on(FlvJs.Events.ERROR, () => {
      stateChangeRef('error');
    });

    instance.load();
    instance.play();

    return () => {
      instance.destroy();
    };
  }, [ref, url, stateChangeRef]);
};

// 拖动
const useDrag = (ref: React.MutableRefObject<HTMLElement>, syncFunc: any, callback?: any) => {
  const [drag, setDrag] = useState(false);
  const [nextKey, setNextKey] = useState({});
  const callbackRef = useMemoizedFn(callback);

  useEffect(() => {
    if (!drag) return;

    const video = ref.current;
    const container = ref.current?.parentElement;
    if (!container) return;

    container.style.cursor = 'crosshair';
    video.style.pointerEvents = 'none';
    const rect = container.getBoundingClientRect();

    // 提示用的 div
    const boundDiv = document.createElement('div');
    boundDiv.style.cssText = 'border: 1px dashed white; pointer-events: none; position: absolute;';
    container.append(boundDiv);

    // 状态值
    let dragStart = { x: 0, y: 0 };
    let dragEnd = { x: 0, y: 0 };

    const mousemove = (e) => {
      dragEnd = {
        x: Math.min(Math.max(e.clientX - rect.x, 0), rect.width),
        y: Math.min(Math.max(e.clientY - rect.y, 0), rect.height),
      };

      // 更新bounds
      boundDiv.style.left = `${Math.min(dragStart.x, dragEnd.x)}px`;
      boundDiv.style.top = `${Math.min(dragStart.y, dragEnd.y)}px`;
      boundDiv.style.width = `${Math.abs(dragEnd.x - dragStart.x)}px`;
      boundDiv.style.height = `${Math.abs(dragEnd.y - dragStart.y)}px`;
    };

    const mouseup = (e) => {
      mousemove(e);
      setNextKey({}); // 继续连续绘制
      // 有效的拖动
      if (dragStart.x !== dragEnd.x && dragStart.y !== dragEnd.y) {
        callbackRef({
          startX: (dragStart.x / rect.width) * 255,
          startY: (dragStart.y / rect.height) * 255,
          endX: (dragEnd.x / rect.width) * 255,
          endY: (dragEnd.y / rect.height) * 255,
        });
      }
    };

    const mousedown = (e) => {
      dragStart = { x: e.clientX - rect.x, y: e.clientY - rect.y };
      window.addEventListener('mousemove', mousemove);
      window.addEventListener('mouseup', mouseup);
    };

    container.addEventListener('mousedown', mousedown);

    return () => {
      container.style.cursor = 'unset';
      video.style.pointerEvents = 'unset';
      container.removeEventListener('mousedown', mousedown);
      window.removeEventListener('mousemove', mousemove);
      window.removeEventListener('mouseup', mouseup);
      boundDiv.remove();
    };
  }, [ref, callbackRef, drag, nextKey]);

  // 同步 drag 状态
  useEffect(() => {
    if (!syncFunc.current) return;
    syncFunc.current(drag);
  }, [drag, syncFunc]);

  return setDrag;
};

// 视频播放器
export const VideoPlayer = memo(
  (props: {
    state?: 'load' | 'error' | 'play';
    url?: string;
    errorText?: string;

    videoRef?: any;
    className?: string;
    append?: React.ReactNode;

    autoPlay?: boolean;
    onEnded?: () => void;
  }) => {
    const { state = 'load', url } = props;

    return (
      <div className={props.className} x-class="relative">
        {/* 视频容器 */}
        <div className="relative h-full">
          <video
            className="h-full w-full"
            style={{ visibility: state !== 'play' ? 'hidden' : 'visible' }}
            controls
            ref={props.videoRef}
            src={url}
            autoPlay={props.autoPlay}
            onEnded={props.onEnded}
          />

          {/* 异常情况下的图片（没有播放地址） */}
          <VideoEmpty x-if={state === 'error'} className="absolute inset-0" text={props.errorText} />

          {/* 初始化中等待动画 */}
          <Spin
            x-if={state === 'load'}
            className="absolute inset-0 flex items-center justify-center bg-[#0000004d]"
            indicator={<LoadingOutlined style={{ fontSize: 48 }} spin />}
          />
        </div>

        {/*  其他的内容 */}
        {state === 'play' ? props.append : null}
      </div>
    );
  },
);

// 控件 - 方向修改
export const DirectionController = memo((props: any) => {
  const { execCommad } = props;

  return (
    <div className={styles['PTZ-container']} style={props.style}>
      <div className={styles['PTZ-control-circle']}>
        <div className={styles['PTZ-control']}>
          {/* 向左上 */}
          <div className={styles['control-btn']}>
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向右上 */}
          <div style={{ transform: ' rotate(90deg)' }} className={styles['control-btn']}>
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向左下 */}
          <div style={{ transform: ' rotate(-90deg)' }} className={styles['control-btn']}>
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向右下 */}
          <div style={{ transform: ' rotate(180deg)' }} className={styles['control-btn']}>
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
        </div>
      </div>

      {/* 中间空白圆圈 */}
      <div className={styles['control-round']}>
        <div className={styles['PTZ-control']}>
          {/* 向上 */}
          <div
            onMouseDown={() => execCommad('UP', 0)}
            onMouseUp={() => execCommad('UP', 1)}
            className={styles['control-btn']}
          >
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向右 */}
          <div
            onMouseDown={() => execCommad('RIGHT', 0)}
            onMouseUp={() => execCommad('RIGHT', 1)}
            style={{ transform: ' rotate(90deg)' }}
            className={styles['control-btn']}
          >
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向左 */}
          <div
            onMouseDown={() => execCommad('LEFT', 0)}
            onMouseUp={() => execCommad('LEFT', 1)}
            style={{ transform: ' rotate(-90deg)' }}
            className={styles['control-btn']}
          >
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
          {/* 向下 */}
          <div
            onMouseDown={() => execCommad('DOWN', 0)}
            onMouseUp={() => execCommad('DOWN', 1)}
            style={{ transform: ' rotate(180deg)' }}
            className={styles['control-btn']}
          >
            <UpOutlined style={{ transform: ' rotate(-45deg)' }} />
          </div>
        </div>
      </div>
    </div>
  );
});

// 控件 - 放大缩小控制
export const ZoomController = memo((props: any) => {
  const { execCommad, direction } = props;
  const [isZoom, setIsZoom] = useState(false);

  return (
    <div className={styles['PTZ-container-2']} x-class={direction || ''} style={props.style}>
      <div className={styles['handle-btn']}>
        <div onMouseDown={() => execCommad('ZOOM_IN', 0)} onMouseUp={() => execCommad('ZOOM_IN', 1)}>
          <ZoomInOutlined />
        </div>
        <div onMouseDown={() => execCommad('ZOOM_OUT', 0)} onMouseUp={() => execCommad('ZOOM_OUT', 1)}>
          <ZoomOutOutlined />
        </div>
      </div>
      <div className={styles['handle-btn']}>
        {/* 聚焦按钮 */}
        <div>
          <AimOutlined />
        </div>
        {/* 3d框选缩放按钮 */}
        <div x-class={{ select: isZoom }} onClick={() => execCommad('3D_ZOOM', !isZoom ? 0 : 1, setIsZoom)}>
          <SelectOutlined />
        </div>
      </div>
    </div>
  );
});

export default React.forwardRef(LiveVideo);
